#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/timer.h>

#define timer_module_STR_LEN 128

typedef struct {
    int major;
    char module_name[timer_module_STR_LEN];
    struct timer_list timer;
    unsigned long long startTime;
    unsigned long long currentTIme;
} timer_module_data;

static timer_module_data g_private_data = {
    .module_name = "timer_module",
};

void timer_module_callback(struct timer_list *timer)
{    
    g_private_data.currentTIme = jiffies_to_msecs(jiffies);
    printk("[%s][%d] time elaspe %llu\n", __func__, __LINE__, g_private_data.currentTIme - g_private_data.startTime);
    mod_timer(timer, jiffies + msecs_to_jiffies(100));
    g_private_data.startTime = g_private_data.currentTIme;
}


static ssize_t timer_module_read(struct file *file, char __user *data, size_t len, loff_t *offset)
{
    printk("[%s][%d]\n", __func__, __LINE__);
    return 0;
}

static ssize_t timer_module_write(struct file *file, const char __user *data, size_t len, loff_t *offset)
{
    printk("[%s][%d]\n", __func__, __LINE__);
    return 0;
}

static const struct file_operations fops = {
    .read = timer_module_read,
    .write = timer_module_write,
};

static int __init timer_module_init(void)
{
    printk("[%s][%d]register char device\n", __func__, __LINE__);
    g_private_data.major = register_chrdev(0, g_private_data.module_name, &fops);
    if (!g_private_data.major) {
        printk(KERN_ERR "register_chrdev failed\n");
        return -ENODEV;
    } else {
        printk("[timer_module]:%s major:%d\n", g_private_data.module_name, g_private_data.major);
    }
    timer_setup(&g_private_data.timer, timer_module_callback, 0);
    g_private_data.startTime = jiffies_to_msecs(jiffies);
    add_timer(&g_private_data.timer);
    
    return 0;
}

static void __exit timer_module_exit(void)
{
    del_timer(&g_private_data.timer);
    unregister_chrdev(g_private_data.major, g_private_data.module_name);
    printk("[%s][%d]unregister device\n", __func__, __LINE__);
}

module_init(timer_module_init);
module_exit(timer_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yujie Guo");
MODULE_DESCRIPTION("Custom Module for Learning");